package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"net/http"
	"path/filepath"
	"strings"
	"time"

	"gitee.com/cxssang/goframe/lib/crypto"

	"gitee.com/cxssang/goframe/lib/sql"

	"log"

	"gitee.com/cxssang/genealogy/act"
	_ "gitee.com/cxssang/genealogy/act/admin"
	_ "gitee.com/cxssang/genealogy/act/mobile"
	"gitee.com/cxssang/genealogy/fs"
)

// 管理端认证
func auth(handlerFunc http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		authKey, err := r.Cookie("auth-key")
		logUrlPath := "/admin/login"
		if r.RequestURI == logUrlPath {
			handlerFunc(w, r)
			return
		}

		if err != nil || authKey.Value == "" {
			http.Redirect(w, r, logUrlPath, http.StatusFound)
			return
		}
		aes := crypto.NewAes()
		decodeId := aes.Decrypt(authKey.Value, string(act.K))
		if decodeId == "" {
			http.Redirect(w, r, logUrlPath, http.StatusFound)
			return
		}
		sq := sql.New()
		user, err := sq.Select("users", sql.NewWhere().Add("id=?", decodeId).Add("is_admin=1"), 0, 0, "id,name", "").FetchOne()
		if err != nil {
			log.Println(err.Error())
			http.Redirect(w, r, logUrlPath, http.StatusFound)
			return
		}
		if user == nil {
			http.Redirect(w, r, logUrlPath, http.StatusFound)
			return
		}
		r.Header.Set("user-id", user.Get("id"))
		r.Header.Set("user-name", user.Get("name"))
		handlerFunc(w, r)
	}
}

// 移动端认证
func mauth(handlerFunc http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		authKey, err := r.Cookie("m-auth-key")
		logUrlPath := "/m/login"
		renameUrlPath := "/m/rename"
		if r.RequestURI == logUrlPath || r.RequestURI == renameUrlPath {
			handlerFunc(w, r)
			return
		}

		if err != nil || authKey.Value == "" {
			http.Redirect(w, r, logUrlPath, http.StatusFound)
			return
		}
		aes := crypto.NewAes()
		decodeId := aes.Decrypt(authKey.Value, string(act.K))
		if decodeId == "" {
			http.Redirect(w, r, logUrlPath, http.StatusFound)
			return
		}
		sq := sql.New()
		user, err := sq.Select("users", sql.NewWhere().Add("id=?", decodeId).Add("is_admin=0"), 0, 0, "id,name,member_id", "").FetchOne()
		if err != nil {
			log.Println(err.Error())
			http.Redirect(w, r, logUrlPath, http.StatusFound)
			return
		}
		if user == nil {
			http.Redirect(w, r, logUrlPath, http.StatusFound)
			return
		}
		r.Header.Set("user-id", user.Get("id"))
		r.Header.Set("user-name", user.Get("name"))
		r.Header.Set("member-id", user.Get("member_id"))
		handlerFunc(w, r)
	}
}

// 根据文件扩展名确定 Content-Type
func contentType(filePath string) string {
	ext := filepath.Ext(filePath)
	switch ext {
	case ".html":
		return "text/html"
	case ".css":
		return "text/css"
	case ".js":
		return "application/javascript"
	case ".jpg", ".jpeg":
		return "image/jpeg"
	case ".png":
		return "image/png"
	// 可以根据需要添加更多的文件类型
	case ".bmp":
		return "image/bmp"
	case ".gif":
		return "image/gif"
	case ".ttf":
		return "application/octet-stream"
	default:
		return ""
	}
}

var handlerFun = func(w http.ResponseWriter, r *http.Request) {
	// 获取请求的路径
	filePath := r.URL.Path
	//处理静态文件
	if contentType(filePath) != "" {
		// 尝试打开文件
		file, err := fs.FS.Open(filePath)
		if err != nil {
			// 文件不存在，返回 404
			http.NotFound(w, r)
			return
		}
		defer file.Close()

		// 获取文件信息
		fileInfo, err := file.Stat()
		if err != nil {
			// 获取文件信息失败，返回 500
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		// 如果是目录，返回 403
		if fileInfo.IsDir() {
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}

		// 设置响应头
		w.Header().Set("Content-Type", contentType(filePath))
		w.Header().Set("Last-Modified", fileInfo.ModTime().Format(time.RFC1123))

		// 服务文件内容
		buf := new(bytes.Buffer)
		_, err = io.Copy(buf, file)
		http.ServeContent(w, r, filePath, fileInfo.ModTime(), bytes.NewReader(buf.Bytes()))
		return
	}
	//处理请求
	if filePath == "/" {
		http.Redirect(w, r, "/m/index", http.StatusMovedPermanently)
		return
	}
	if handler, ok := act.HandleFunMap[filePath]; ok {
		if strings.Index(filePath, "/m/") == 0 {
			mauth(handler)(w, r)
		} else {
			auth(handler)(w, r)
		}
		return
	}
	http.NotFound(w, r)
}

func init() {
	//fmt.Println([]byte("rqqfC2YRGcOB"))
	err := sql.Connect("sqlite3", "default", "./data.db", true)
	if err != nil {
		log.Fatal(err)
	}
	sq := sql.New()
	_, err = sq.ExecSql("create table if not exists members(id INTEGER primary key autoincrement,name text,sex int,birth text,spouse text,parent_id int,address text,phone text,remark text)")
	if err != nil {
		log.Fatal(err)
	}
	_, err = sq.ExecSql("create table if not exists setting(key text primary key,value text)")
	if err != nil {
		log.Fatal(err)
	}
	table, err := sq.Raw("select name from sqlite_master where name='users' limit 1").FetchOne()
	if err != nil {
		log.Fatal(err)
	}
	if table == nil {
		_, err = sq.ExecSql("create table if not exists users(id integer primary key autoincrement,name text,password text,member_id int default 0 not null,login_time text,login_ip text,is_admin int default 0 not null,disabled int default 0 not null)")
		if err != nil {
			log.Fatal(err)
		}
		sq.ExecSql("insert into users(name,password,is_admin) values('admin','21232f297a57a5a743894a0e4a801fc3',1)")
	}
}

func main() {
	ip := flag.String("ip", "0.0.0.0", "监听IP")
	port := flag.String("port", "8590", "监听端口")
	flag.Parse()
	listen := fmt.Sprintf("%s:%s", *ip, *port)
	fmt.Println(listen)
	http.HandleFunc("/", handlerFun)
	log.Fatal(http.ListenAndServe(listen, nil))
}
